/*
 * StepItem
 * 
 * versvion 1.0
 * 
 * 15.05.2009
 * 
 * Copyright (c) StrongQA, Inc.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of StrongQA, Inc.
 * You shall not disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with StronQA.Inc.
 *
 */

package reporting;

import java.util.*;
import java.util.Map.Entry;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

import core.SeleneseTestCaseEx;
import static util.ConstantCollection.*;
import util.*;

/**
 * @author Roman I.
 *
 */

public class ReportEngine {	
	
	/**
	 * collection that contains names of reports 
	 */
	private HashMap<String, XReport> dictReports = new HashMap<String, XReport>();	
	
	private Util u = new Util();
	private FileWork fw = FileWork.getInstance();
	
	/**
	 * object tc contains all properties of tests
	 */
	private TestConfiguration tc = TestConfiguration.getInstance();	
	
	/**
	 * variable step contains step of testcase 
	 */
	private TCStep step;
	
	/**
	 * variable lastStepId is numerator of testcase's steps
	 */
	private Integer lastStepId = 0;
	
	///**
	//* variable lastStepTime contains time of last testcase's steps
	//*/
	//private Date lastStepTime = new Date();
		
	/**
	 * variable actionErrorId is numerator of steps error actions
	 */
	private Integer actionErrorId = 0;
	
	/**
	 * manage reports, determines all actions, that related with reports
	 */
	public ReportEngine() {		
		initialize();
	}
	
	
	
    /**
	 * @return dictReports - collection that contains names of reports 
	 */
	public HashMap<String, XReport> getDictReports() {
		return dictReports;
	}
	
    /**
     * @return step of testcase
     */
    public TCStep getStep() {
    	return step;
    }
    
    private void initialize() {
    	FileWork fw = FileWork.getInstance();
		String headerText = "";
		Util u = new Util();
		
		headerText = "-------------------------------------------------------------------------------------\n" ;
		headerText = headerText + "Test title:\t" + tc.getEnv("_testtitle") + "\n";
		headerText = headerText + "Test name:\t" + tc.getEnv("_testname") + "\n";
		headerText = headerText + "Product:\t" + tc.getEnv("product") + "\n";
		headerText = headerText + "Release:\t" + tc.getEnv("release") + "\n";
		headerText = headerText + "Server:\t" + SeleneseTestCaseEx.getServerName() + "\n";
		headerText = headerText + "Browser:\t" + SeleneseTestCaseEx.getBrowser() + "\n";
		headerText = headerText + "Time zone:\t" + u.getTimeZone() + "\n";
		headerText = headerText + "Text log started:\t" + u.getDateTimeNow() + ".\n";
		headerText = headerText + "-------------------------------------------------------------------------------------\n" ;
			
		addToConsole(headerText);
		
		if(!tc.getEnv("pathtologs").contentEquals("[NO FOUND]")) { 
			if (!fw.existsFileOrDir(tc.getEnv("pathtologs"))) {
				System.err.println("The '" + tc.getEnv("lpathtologs") + "' does not exists. The log will be save to 'log' folder of project.");
			}
		}
												
		DateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
        Date date = new Date();
        tc.setEnv("_testexec", dateFormat.format(date));
               	
		if(!fw.existsFileOrDir(u.getFullPathToLog("datetime"))){
			fw.createDirs(u.getFullPathToLog("datetime"));
		}
		
		if (tc.getEnv("getscrshot").toLowerCase().contentEquals("true")) {
			if(!fw.existsFileOrDir(u.getFullPathToLog("scrsht"))){
				fw.createDirs(u.getFullPathToLog("scrsht"));
			}
		}
		
		//Add reports
		String [] temppair = null;
		String [] temp = null;
		temppair = tc.getEnv("appliedreports").split("\\;");
		if (temppair.length == 0){
			System.out.println("Please, set 'appliedreports' variable correctly in configuration file!");
		}
		
		for (int i = 0 ; i < temppair.length ; i++) {
		  temp = temppair[i].split("\\@");
		  if (temp.length == 2){
			  addReport(temp[0], temp[1]);
		  }  
		}
    }

	/**
	 * Add element to the collection that contains names of reports (dictReports).
	 * @param dictReports - collection that contains names of reports 
	 */
	private void addElementToDictReports(String key, XReport value) {
		dictReports.put(key, value);
    }	
	
    /**
     * Add new report, type can be html, txt or console.
     * @param typeReport type of record, can be txt, html etc.
     * @param nameReport simple name of report
     */
    public void addReport(String typeReport, String nameReport){
    	typeReport = typeReport.toLowerCase();
    	typeReport = typeReport.trim();
    	String key;
    	TemplateReport reporterX;
   		if (typeReport.contentEquals("html")){
   			key = typeReport.concat("_").concat(nameReport);   
			if(!getDictReports().containsKey(key)){
				reporterX = new HtmlReport(nameReport);
			}
			else{
				System.out.println("There is no '" + typeReport + "' type report");
				return;
			}
				
		}
		else if(typeReport.contentEquals("txt")){
				key = typeReport.concat("_").concat(nameReport);
				if(!getDictReports().containsKey(key)){
					reporterX = new TxtReport(nameReport);
				}
				else{
					System.out.println("There is no '" + typeReport + "' type report");
					return;
				}
		}
		else if(typeReport.contentEquals("xls")){
			key = typeReport.concat("_").concat(nameReport);
			if(!getDictReports().containsKey(key)){
				reporterX = new ExcelReport(nameReport);
			}
			else{
				System.out.println("There is no '" + typeReport + "' type report");
				return;
			}
	}
		else{
			System.out.println("addReport:: Type '" + typeReport + "' was not found!");
			return;
		}
   		
   		addElementToDictReports(key, reporterX);
			
    }	
    
    /**
     * Add new step of test case, and passes it to addToConsole method.
     * @param id Identifire
     * @param name of actions, title of message
     */
    public void newStep(String id, String name) {
    	TCStep step = new TCStep(id, name);
    	
    	addToConsole("STEP:" + id + ". (" + u.getTime(step.getTime()) + ")" + step.getName());
    	this.step = step;
    	lastStepId = lastStepId + 1;
    	//lastStepTime = step.getTime();
    }
    
    /**
     * Create new step (with Id) of test case, and passes it to addToConsole method.
     * @param name of actions, title of message
     */
    public void newStep(String name) {
    	Integer id = lastStepId + 1;
    	TCStep step = new TCStep(id.toString(), name);
    	
    	addToConsole("STEP:" + step.getId() + ". (" + u.getTime(step.getTime()) + ")" + step.getName());
    	this.step = step;
    	lastStepId = id;
    	//lastStepTime = step.getTime();
    }
    
    /**
     * Does reporting of step TC for defined reports.
     */
    public void reportStep() {
    	addToConsole("SUMMARY: " + getStatusName(step.getStatus()) + "\n");
    	
    	Map.Entry<String, XReport> entry = null;
    	Iterator<Entry<String, XReport>> it = getDictReports().entrySet().iterator();
    	while(it.hasNext()){
             entry = (Map.Entry<String, XReport>)it.next();
             XReport report = entry.getValue();
             report.reportStep(step);
        }
    }
    
    /**
     * Add new action of test case, and passes it to addToConsole method.
     * @param description of action
     */
    public void newAction(String description) {
    	addToConsole("	ACTION: " + description);
    	step.addToCollection("action", description);
    }
    
    /**
     * Add new check of test case, and passes it to addToConsole method.
     * @param description of action
     */
    public void newCheck(String description) {
    	addToConsole("	CHECK: " + description);
    	step.addToCollection("cp", description);
    }
    
    /**
     * Define status of action/check, and add it to console. Set path to screenshot
     * @param status get status from list "STATUS_INFO, STATUS_UNCHECKED, STATUS_DONE, STATUS_PASS"...
     * @param description Error or warning description
     * @param pathToScrShot
     */
    public void addResult(Integer status, String description, StackTraceElement[] errorStack, String pathToScrShot) {
    	List<StepItem> itemCollection = step.getItemCollection();
    	StepItem stepItem = itemCollection.get(itemCollection.size() - 1);
    			
		/* All actions should have status DONE if they were completed successfully*/
		if (stepItem.getType().contentEquals("action") && status == STATUS_PASS) {
			status = STATUS_DONE; //TODO needs for refactoring in future
		}
		
    	addToConsole(status, "	STATUS: " + getStatusName(status));
    	step.setItemStatus(status, description, errorStack);
    	
    	if (pathToScrShot != null) {
    		step.setScrShot(pathToScrShot);
    	}
    	
    	if (errorStack != null) {
    		step.setTrace(dumpErrorStackToFile(errorStack));
    	}
    	
    }
    
    /**
     * Send to console input information .
     * @param text Text that display in console
     */
    private void addToConsole(String text) {
    	addToConsole(0, text);
    }
    
    /**
     * Send to console input information .
     * @param status Message status
     * @param text Text that display in console
     */
    private void addToConsole(Integer status, String text) {
    	switch(status) {
		case STATUS_ERROR: 
			System.err.println(text);
			break;
		default:
			if (tc.getEnv("addstepstoconsole").toLowerCase().contentEquals("true")) {
	    		System.out.println(text);
	    	}
			break;
		}
    }
    
    /** It is bridge for external using in TestCases
     * @return Id current steps 
     */
    public String getStepId() {
    	return step.getId();
    }
    
    /**
     * create and write to file error description of action
     * @param errorStack array of error description
     * @return path to file
     */
    private String dumpErrorStackToFile(StackTraceElement[] errorStack) {
    	String path;
    	String errorMessage = "";
    	String spase = "";
    	actionErrorId ++;
    	path = u.getFullPathToLog("datetime") + "source/trace/";
    	for(int i = 0; i < errorStack.length; i++) {
     		errorMessage = errorMessage + spase +
    		errorStack[i].getFileName() + ":" + 
    		errorStack[i].getClassName() + "." +
    		errorStack[i].getMethodName() + " :" + 
    		errorStack[i].getLineNumber() + "\n";
  			spase += " ";
    	}
    	
    	if(!fw.existsFileOrDir(path)) {
    		fw.createDirs(path);
    	}
    	
    	String fileName;
    	fileName = step.getId() + "_" + actionErrorId.toString() + ".txt"; 
    	if (fw.writeFile(path + fileName, errorMessage)) {
    		return fileName;
    	} else {
    		return null;
    	}
   }

}